﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Drawing;
using LED_Editor.Model;

namespace LED_Editor.Controls
{
    public class LedPreviewComponent:Component
    {

        

        public LedPreviewComponent()
        {
            InitializeComponent();
            Ratio = 1;
        }

        public LedPreviewComponent(IContainer container)
        {
            container.Add(this);
            InitializeComponent();
            Ratio = 1;
        }

        /// <summary> 
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }


        private System.Windows.Forms.Timer timer1;
        private IContainer components;

        private void InitializeComponent()
        {
            this.components = new System.ComponentModel.Container();
            this.timer1 = new System.Windows.Forms.Timer(this.components);
            // 
            // timer1
            // 
            this.timer1.Interval = 1;
            this.timer1.Tick += new System.EventHandler(this.timer1_Tick);

        }

        public event EventHandler<LedPreviewStateEventArgs> LedPreviewStateChanged;

        private void OnLedPreviewStateChanged(LedPreviewControlling state)
        {
            if (LedPreviewStateChanged != null)
            {
                LedPreviewStateChanged(this, new LedPreviewStateEventArgs() { PreviewControllingState = state });
            }
        }

        public event EventHandler<LedPreviewControllingEventArgs> LedPreviewControllingChanged;

        private void OnLedPreviewControllingChanged(int elapsed, Color color)
        {
            if (LedPreviewControllingChanged != null)
            {
                LedPreviewControllingChanged(this, new LedPreviewControllingEventArgs() { Elapsed = elapsed, ElapsedMilliseconds = (int)ElapsedMilliseconds, EffectColor = color });
            }
        }


        public Controller Controller { get; set; }

        private int _elapsedIntervals;


        private float ElapsedMilliseconds
        {
            get { return (float)ElapsedIntervals*10; }
        }
        private int ElapsedIntervals
        {
            get { return _elapsedIntervals; }
        }

        private int _elapsedTicksInternal;

        private int _ratio;
        public int Ratio
        {
            get { return _ratio; }
            set
            {
                if (value <= 0)
                {
                    _ratio = 1;
                }
                else
                {
                    _ratio = value;
                }
            }
        }



        private int _previousFrameIndex;
        private int _framesDurationElapsed;

        private void timer1_Tick(object sender, EventArgs e)
        {
            if (Controller.Frames.Count == 0)
            {
                Stop();
                return;
            }


            _elapsedTicksInternal += 1;

            if (_elapsedTicksInternal != 0 && Ratio != 1 && _elapsedTicksInternal % Ratio != 0)
                return;

            _elapsedIntervals += 1;





            int frameIndex = Controller.GetFrameIndexByElapsedTime(ElapsedIntervals);

            if (frameIndex == -1)
            {
                Stop();
                return;
            }

            FrameStruct frame = Controller.GetFrameByElapsedTime(ElapsedIntervals);

            if (frameIndex != _previousFrameIndex)
            {
                _framesDurationElapsed += Controller.Frames[_previousFrameIndex].Duration ;
                _previousFrameIndex = frameIndex;
            }
            byte R = (byte)(frame.StartR + (byte)((frame.EndR - frame.StartR) * (ElapsedIntervals - _framesDurationElapsed) / frame.Duration));
            byte G = (byte)(frame.StartG + (byte)((frame.EndG - frame.StartG) * (ElapsedIntervals - _framesDurationElapsed) / frame.Duration));
            byte B = (byte)(frame.StartB + (byte)((frame.EndB - frame.StartB) * (ElapsedIntervals - _framesDurationElapsed) / frame.Duration));


            PreviewColor = Color.FromArgb(R, G, B);
            OnLedPreviewControllingChanged((int)ElapsedMilliseconds , PreviewColor);
            if (ElapsedIntervals  >= Controller.TotalFramesDuration)
            {
                Stop();
            }

        }
   
        private Color _previewColor;
        protected Color PreviewColor
        {
            get {
                return _previewColor;
            }
            set {
                if (_previewColor.ToArgb() != value.ToArgb())
                {
                    _previewColor = value;
                }
            }
        }


        private void button1_Click(object sender, EventArgs e)
        {
            if (timer1.Enabled)
            {
                Stop();
            }
            else
            {
                Start();
            }

        }

        public bool Enabled
        {
            get { return timer1.Enabled; }
        }
        public  void Start()
        {
            if (ElapsedMilliseconds == 0)
            {
                FrameStruct frame = Controller.Frames.FirstOrDefault<FrameStruct>();
                PreviewColor = Color.FromArgb(frame.StartR, frame.StartG, frame.StartB);
                OnLedPreviewControllingChanged(ElapsedIntervals, PreviewColor);
            }

            timer1.Start();
            OnLedPreviewStateChanged(LedPreviewControlling.Start);
        }


        public void Stop()
        {
            timer1.Stop();
           _previousFrameIndex=0;
         _framesDurationElapsed=0;

            _elapsedIntervals  = 0;
            _elapsedTicksInternal = 0;
            OnLedPreviewStateChanged(LedPreviewControlling.Stop);
        }

       
        internal Color GetColorByElapsedMilliseconds(double milliseconds)
        {
            int intervals = (int)milliseconds / 10;

            FrameStruct frame = Controller.GetFrameByElapsedTime(intervals);

            if (frame.ColorsAreEqual  )
                return frame.StartColor ;

            byte R = 0;
             byte G = 0;
             byte B = 0;

             if (frame.Duration != 0)
             {
                 R = (byte)(frame.StartR + (byte)((frame.EndR - frame.StartR) * (intervals - frame.StartMarker) / frame.Duration));
                 G = (byte)(frame.StartG + (byte)((frame.EndG - frame.StartG) * (intervals - frame.StartMarker) / frame.Duration));
                 B = (byte)(frame.StartB + (byte)((frame.EndB - frame.StartB) * (intervals - frame.StartMarker) / frame.Duration));
             }


            return Color.FromArgb(R, G, B);

        }
    }

    public enum LedPreviewControlling
    {
        Start,
        Stop
    }

    public interface IBackColor
    {
        Color BackColor { get; set; }
    }

    public class LedPreviewStateEventArgs : EventArgs
    {
        public LedPreviewControlling PreviewControllingState { get; set; }
    }

    public class LedPreviewControllingEventArgs : EventArgs
    {
        public int Elapsed { get; set; }
        public int ElapsedMilliseconds { get; set; }
        public Color EffectColor { get; set; }
    }
}
